#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <string.h>

#define TAM_STRING 100
#define NUMTHREAD_PLNDRM 4
#define NUMTHREAD_CRIVO 1

int inferior(int id, int p, int n)
{
	return ((id*n)/p);
}

int superior(int id, int p, int n)
{
	int aux = 0;
	aux = inferior(id+1,p,n-1);
	return aux; 
}

void zera_string(char *c, int n)
{
    int i = 0;

    for(i = 0; i < n; i++)
        c[i] = 0;
}

int palindromo(char *string)
{
    int i;
    int j;
    int k;
    int tam = strlen(string);
    int soma_ascii = 0;

    j = tam-1;

    //ignora caracteres especiais no final de palavra;
    for(k = j; k >= 0; k--)
	if((int)string[k] < 65 || ((int)string[k] > 90 && (int)string[k] < 97) || (int)string[k] > 122)
		j--;
	else
		break;

    //ignora caracteres especiais no início de palavra;
    for(k = 0; k <= j; k++)
	if((int)string[k]<65 || ((int)string[k]>90 && (int)string[k]<97) || (int)string[k]>122 )
		i++;
	else
		break;

    //teste se é palíndromo;
    if(j == -1)
        return 0;//palavra só com caracteres especiais;
    for( ;i <= j; i++)
    {
        if(((int)string[j] != (int)string[i]) && ((int)string[j]+32 != (int)string[i])   && ((int)string[j] != (int)string[i]+32))
            return 0;
        else
        {
            if(i != j)
                soma_ascii += (int)string[j] + (int)string[i];
            else
                soma_ascii += (int)string[i];
        }
        j--;
    }

    return soma_ascii;

}

int extremos(FILE *fp, int posicao)
{
    fseek(fp,posicao,SEEK_SET);
    char c = fgetc(fp);
    int i = 0;

    while(c != ' ' && c != '\t' && !feof(fp)) {
        c = fgetc(fp);
        i++;
    }

    return i+posicao;
}

int main(int argc, char *argv[]) {
    char aux[TAM_STRING];
    char **texto = (char**)malloc(sizeof(char*));
    int palindromo_ascii = 0;
    int texto_i = 0;
    int i = 0;
    int j = 0;
    int pa;
    int palin = 0;
    int boole = 0;
    int primo = 0;
    int primo_global = 0;
    int soma_plndrm = 0;
    int soma_primo = 0;
    int pos_arquivo;
    int pt_f = 0;
    int pt_i = 0;

    FILE *fp;
    int inicio, fim, tamanho_arq;

    if((fp = fopen("wikipedia.txt","r")) == NULL)
    {
        printf("Erro.\n");
        exit(1);
    }

    fseek(fp,0,SEEK_END);
    tamanho_arq = ftell(fp);

    //encontra o início do bloco.
    omp_set_num_threads(NUMTHREAD_PLNDRM);

    pt_i = inferior(j,10,tamanho_arq);
    pt_f = superior(j,10,tamanho_arq);
    fseek(fp,0,SEEK_SET);

    while(pt_f <= tamanho_arq )
    {
	    pa = 0; primo =
	    0;
	    pos_arquivo = ftell(fp);
	    texto_i = 0;
	    i = 0;

	    while(pos_arquivo < pt_f)
	    {
			fscanf(fp,"%s",aux);
			pos_arquivo = ftell(fp);
			texto = (char**)realloc(texto,sizeof(char*)*(texto_i+1));
			texto[i] = (char*)malloc(sizeof(char)*(strlen(aux)+1));
			strcpy(texto[i],aux);
			zera_string(aux,TAM_STRING);
			texto_i++;
			i++;
	    }
	    #pragma omp parallel firstprivate(palindromo_ascii, i, texto_i, boole, aux), shared(fp,pt_f,pt_i,tamanho_arq,texto), private(inicio, pos_arquivo, fim) reduction(+:primo_global,palin)
	    {
		    primo_global = 0; palin = 0;
		    int rank = omp_get_thread_num();

		    inicio = inferior(rank,NUMTHREAD_PLNDRM,texto_i);
		    fim = superior(rank,NUMTHREAD_PLNDRM,texto_i);

		    zera_string(aux,TAM_STRING);

		    i = inicio;
		    while(i <= fim)
		    {
                palindromo_ascii = palindrome(texto[i]);
                if (palindromo_ascii > 0)
                {
                    palin += 1;
                    boole = crivo(NUMTHREAD_CRIVO,palindromo_ascii);
                    primo_global += boole;
                }
                i++;
		    }

	    }
	    #pragma omp barrier
	    j++;
	    pt_f = superior(j,10,tamanho_arq);
	    pt_i = inferior(j,10,tamanho_arq);
	    pt_i = extremos(fp,pt_i);

	   i = 0;
	   while(i < texto_i)
	   {
        free(texto[i]);
				i++;
	   }
    }

	free(texto);
    printf("Primo global: %d\n",primo_global);
    printf("Palindromo: %d\n",palin);
    fclose(fp);

    return 0;
 }


